package com.sxsihe.heartmate.view;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.util.AttributeSet;
import android.view.View;

import com.sxsihe.heartmate.R;
import com.sxsihe.heartmate.util.SharePreferenceUtil;

import java.text.SimpleDateFormat;
import java.util.*;

public class CurveView extends View {

    private Paint bmpPaint;
    private Paint linePaint;
    public Paint axisPaint ;
    private Paint mPaint2;
    private int step = 28;
    private LinkedList<Point> mPoints;
    private float startX = 0;
    private float startY = 0;
    int count = 0;	private  String x_mark= "";
    Canvas cacheCanvas = null;

    private ArrayList<Integer> xAxis = new ArrayList();
    private ArrayList<Integer> yAxis = new ArrayList();
    private int mBottom = 0;
    private int mHeight = 0;
    private int mLeft = 0;
    private int mWidth = 0;
    private int signal;
    private int devStatus;
    private float mPixPerHeight = 0;
    private float mPixPerWidth = 0;
    private int maxPoint = 0;
    private int currentPoint = 0;
    private int maxValue = 0;
    private int minValue = 0;
    public CurveView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initView(context);
    }

    public CurveView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView(context);
    }

    public CurveView(Context context) {
        super(context);
        initView(context);
    }

    SharePreferenceUtil spu ;

    private void initView(Context context) {
        if (spu == null) {
            spu = SharePreferenceUtil.getInstance(context);
        }

        mBottom = this.getBottom();
        mWidth = this.getWidth();
        mLeft = this.getLeft();
        mHeight = this.getHeight();

        mPixPerHeight = (float)mHeight/(maxValue  - minValue);
        mPixPerWidth =  (float)mWidth/maxPoint ;



        bmpPaint = new Paint();
        bmpPaint.setAntiAlias(true);
        bmpPaint.setFilterBitmap(true);
        bmpPaint.setColor(spu.getColor("color_bg"));

        linePaint = new Paint();
        linePaint.setColor(spu.getColor("color_line"));
        linePaint.setStyle(Paint.Style.STROKE);
        linePaint.setAntiAlias(true);
        linePaint.setFilterBitmap(true);
        linePaint.setStrokeWidth(2);

        mPaint2 = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint2.setColor(spu.getColor("color_coordinate"));
        mPaint2.setStrokeWidth(2);
        mPaint2.setTextSize(25);
        mPaint2.setAntiAlias(true);
        mPaint2.setDither(true);

        axisPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        axisPaint.setColor(spu.getColor("color_text"));
        axisPaint.setStrokeWidth(2);
        axisPaint.setTextSize(25);
        axisPaint.setAntiAlias(true);
        axisPaint.setDither(true);
    }

    Bitmap mBufferBitmap;
    Bitmap signalBitmap;
    Canvas mCanvas;
    Path path;

    @Override
    protected void onDraw(Canvas canvas) {
//        canvas = mCanvas;
//        mBufferBitmap = Bitmap.createBitmap(getCurveViewWidth(), getCurveViewHeight(), Bitmap.Config.ARGB_8888);
//        canvas.setBitmap(mBufferBitmap);
        canvas.drawColor(spu.getColor("color_bg"));

        int width = getCurveViewWidth();
        int height = getCurveViewHeight();


        for (int i = width/2; i < width; i += step) {
            if ((i-width/2)  % (step * 5) == 0) {
                mPaint2.setStrokeWidth(3);
                if(!xAxis.contains(i))
                    xAxis.add(i);
            }else {
                mPaint2.setStrokeWidth(1);
            }
            canvas.drawLine(i, 0, i, height, mPaint2);
        }

        for (int i = width/2; i >0; i -= step) {
            if ((width/2-i)  % (step * 5) == 0) {
                mPaint2.setStrokeWidth(3);
                if(!xAxis.contains(i))
                    xAxis.add(i);
            }else {
                mPaint2.setStrokeWidth(1);
            }
            canvas.drawLine(i, 0, i, height, mPaint2);
        }


        for (int i = height/2; i < height; i += step) {
            if ((i-height/2) % (step * 5) == 0) {
                mPaint2.setStrokeWidth(3);
                if(!yAxis.contains(i))
                    yAxis.add(i);
            }
            else {
                mPaint2.setStrokeWidth(1);
            }
            canvas.drawLine(0, i, width, i, mPaint2);
        }
//		/*2*/
        for (int i = height/2; i >0 ; i -= step) {
            if ((height/2-i) % (step * 5) == 0) {
                mPaint2.setStrokeWidth(3);
                if(!yAxis.contains(i))
                    yAxis.add(i);
            }
            else {
                mPaint2.setStrokeWidth(1);
            }
            canvas.drawLine(0, i, width, i, mPaint2);
        }

        Collections.sort(xAxis);
        Collections.sort(yAxis);
        int point_x = 0;
        int point_y = yAxis.size()/2;

        for(int y : yAxis){
            canvas.drawText(point_y+"", xAxis.get(0)-step-15, y+step+10, axisPaint);
            point_y-=1;
        }





//        canvas.drawText("(s)", xAxis.get(0)+step*3, yAxis.get(yAxis.size()-1)+step*2, axisPaint);
        canvas.drawText("(mV)", 15, yAxis.get(yAxis.size()-2)-step*2, axisPaint);


        if (prepare()) {
            if (mPoints.size() >= width) {
                for (int i = 0; i < width; i++) {
                    mPoints.removeFirst();
                    if(i==(width-1)){
                        x_mark = convert2String(new Date().getTime(),TIME_FORMAT);
                    }
                }
            }
            float pts[] = convertToPts();
            if (pts.length < 1)
                return;

            if(!x_mark.equals("")){
                canvas.drawText(x_mark, xAxis.get(xAxis.size()-2), yAxis.get(yAxis.size()-1)+step, axisPaint);
            }
            canvas.drawLines(pts, linePaint);

        }
//        canvas.drawBitmap(mBufferBitmap, 0, 0, bmpPaint);
//        canvas.drawLines(convertToPts(), mPaint);
    }


    public void drawLogo(){
        Bitmap bmp= BitmapFactory.decodeResource(getResources(), R.drawable.zhc_logo_view);
        mCanvas.drawBitmap(bmp, getCurveViewWidth() - bmp.getWidth() - 30, getCurveViewHeight() - bmp.getHeight() - 30, bmpPaint);
    }
    public void drawSignal(){
//        Bitmap bmp = BitmapFactory.decodeResource(getResources(), R.drawable.signal_unknow);
//        if (signal == 200) {
//            bmp= BitmapFactory.decodeResource(getResources(), R.drawable.signal_strong);
//        } else {
//            bmp= BitmapFactory.decodeResource(getResources(), R.drawable.signal_weak);
//        }
//        mCanvas.drawBitmap(bmp,  100, getCurveViewHeight() - bmp.getHeight() - 30, paint);
    }
    public void drawDevStatus(){
//        Bitmap bmp = BitmapFactory.decodeResource(getResources(), R.drawable.dev_status_not_found);
        switch (devStatus) {

//            case TGDevice.STATE_CONNECTING:
//                bmp = BitmapFactory.decodeResource(getResources(), R.drawable.dev_status_connecting);
//                break;
//            case TGDevice.STATE_CONNECTED:
//                bmp = BitmapFactory.decodeResource(getResources(), R.drawable.dev_status_connected);
//                break;
//            case TGDevice.STATE_NOT_FOUND:
//                bmp = BitmapFactory.decodeResource(getResources(), R.drawable.dev_status_not_found);
//                break;
//            case TGDevice.STATE_DISCONNECTED:
//                bmp = BitmapFactory.decodeResource(getResources(), R.drawable.dev_status_disconnect);
//                break;
        }
//        mCanvas.drawBitmap(bmp,  30, getCurveViewHeight() - bmp.getHeight() - 30, paint);
    }

    // 获取一系列点的曲线路径
    private Path getPointCurvePath(List<Point> points)
    {
        Point startp;
        Point endp;
        Point p3 = new Point();
        Point p4 = new Point();
        Path path = new Path();
        if (null == points || 0 == points.size())
        {
            return path;
        }
        startp = points.get(0);
        path.moveTo(startp.x%getWidth(), startp.y+getHeight()/2);
        int xCenter, yCenter;

        for (int i = 0; i < points.size() - 1; i+=25)
        {
            startp = points.get(i);
            endp = points.get(i+1);
            xCenter = (int)(startp.x%getWidth() + endp.x%getWidth()) / 2;
            yCenter = (int)(startp.y + endp.y) / 2+getHeight()/2;
            p3.y = startp.y+getHeight()/2;
            p3.x = xCenter;
            p4.y = endp.y+getHeight()/2;
            p4.x = xCenter;
            // 确定曲线的路径
            path.cubicTo(p3.x, p3.y, p4.x, p4.y, endp.x%getWidth(), endp.y);
            // path.quadTo(xCenter, yCenter,  endp.x, endp.y);
        }

        return path;
    }

    private float[] getLastHundredPts(float[] pts, int offset) {
        if (pts.length < offset) {
            return pts;
        }
        return Arrays.copyOfRange(pts, pts.length - offset, pts.length - 1);
    }

    private int partition(float[] pts, float right) {
        for (int i = 0; i < pts.length; i += 2) {
            if (right == pts[i]) {
                return i;
            }
        }
        return 0;
    }

    private float getRightPoint(float[] pts) {
        if (pts.length >= 2) {
            return pts[pts.length - 2];
        }
        return pts[0];
    }

    private float[] convertToPts() {
        int height = getCurveViewHeight();
        int size = (mPoints.size() - 1) * 4;
        if (size < 0) {
            size = 0;
        }
        float[] pts = new float[size];

        for (int i = 0; i < size; i++) {
            int pointIndex = (i + 2) / 4;
            if (i % 2 == 1) {
                pts[i] = mPoints.get(pointIndex).y + height / 2;
//               if(pointIndex>0) {
//                   pts[i] = filter(pts[i-2], pts[i]);
//               }
            } else {
                pts[i] = mPoints.get(pointIndex).x % getCurveViewWidth();
            }
        }
        return pts;
    }

    //振幅
    float amplitude = 30;

    //过滤一部分值
    float filter(float _value, float value) {
//        if ( Math.abs( value - _value) < amplitude )
//            return _value;
        return value;

    }


//    private float[] convertToPts() {
//        int height = getCurveViewHeight();
//        int size = (mPoints.size() - 1) * 4;
//        float[] pts = new float[size];
//
//        for (int i = 0; i < size; i++) {
//            int pointIndex = (i + 2) / 4;
//            if (i % 2 == 1) {
//                pts[i] = mPoints.get(pointIndex).y + height/2;
//            } else {
//                pts[i] = mPoints.get(pointIndex).x;
//            }
//        }
//        printFloatArr(pts);
//        return pts;
//    }

    public void printFloatArr(float[] arr) {
        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i] + "   ");
        }
    }

    private boolean prepare() {
        if (mPoints == null || mPoints.isEmpty()) {
            return false;
        }
        return true;
    }


    public void addPoint(Point point) {
        if (this.mPoints == null) {
            this.mPoints = new LinkedList<Point>();
        }
        this.mPoints.addLast(point);
        invalidate();
    }

    public void addVisiablePoint(Point point) {
        addPoint(point);
        //scrollToPoint(point);
    }

    public void pushRaw(int x)
    {
        //int xx = (int)(x*(1.8/4096))/2000;
//        if (isOverStep())
//            count = 0;

        addVisiablePoint(new Point(count, x/33));
        count++;
    }

    public void toggleDevSignal(int signal) {
        this.signal = signal ;
        invalidate();
    }
    public void toggleDevStatus(int devStatus) {
        this.devStatus = devStatus ;
        invalidate();
    }


    private void scrollToPoint(Point point) {
        scrollTo(point.x - getCurveViewWidth(), 0);
    }


    public void clearScreen() {
        if (this.mPoints == null || this.mPoints.isEmpty()) {
            return;
        }
        this.mPoints.clear();
        invalidate();
    }

//    @Override
//    public boolean onTouchEvent(MotionEvent event) {
//        switch (event.getAction()) {
//        case MotionEvent.ACTION_DOWN:
//            startX = event.getX();
//            startY = event.getY();
//            return true;
//        case MotionEvent.ACTION_MOVE:
//            float newX = event.getX();
//            float newY = event.getY();
//            scrollBy((int) (startX - newX), (int) (startY - newY));
//            startX = newX;
//            startY = newY;
//            break;
//        case MotionEvent.ACTION_UP:
//            int sx = getScrollX();
//            int sy = getScrollY();
//            int mWidth = getTotalWidth();
//            int vWidth = getCurveViewWidth();
//            if (mWidth < vWidth) {
//                scrollTo(mWidth - vWidth, 0);
//            }
//            else if (sx < 0) {
//                if (sy < -10 || sy > 10) {
//                    scrollBy(-sx, -sy);
//                } else {
//                    scrollBy(-sx, 0);
//                }
//            }
//
//            else if (sx > (mWidth - vWidth)) {
//                if (sy < -10 || sy > 10) {
//                    scrollBy(mWidth - sx - vWidth, -sy);
//                } else {
//                    scrollBy(mWidth - sx - vWidth, 0);
//                }
//            }
//            else {
//                if (sy < -10 || sy > 10) {
//                    scrollBy(0, -sy);
//                }
//            }
//            break;
//        }
//        return super.onTouchEvent(event);
//    }

    public int getTotalWidth() {
        if (this.mPoints == null || this.mPoints.isEmpty()) {
            return 0;
        }
        return this.mPoints.getLast().x;
    }

    private int getCurveViewHeight() {
        return this.getHeight();
    }

    private int getCurveViewWidth() {
        return this.getWidth();
    }


    public static String TIME_FORMAT = "HH:mm:ss";

    public static String convert2String(long time,String format) {
        SimpleDateFormat sf = new SimpleDateFormat(format);
        Date date = new Date(time);
        return sf.format(date);

    }
}
